package net.kehuilai.tools;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.SimplePropertyPreFilter;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;

/**
 * Created by andy,genghz on 16/12/22.
 */
public class JsonConverter {

    private static final Logger log = LoggerFactory.getLogger(JsonConverter.class);
    private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();

    static {
        /* to enable standard indentation ("pretty-printing") */
//        OBJECT_MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
        /* to allow coercion of JSON empty String ("") to null Object value */
        OBJECT_MAPPER.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT);
        /* to write java.util.Date, Calendar as number (timestamp) */
        OBJECT_MAPPER.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_READING_DUP_TREE_KEY);
        // to prevent exception when encountering unknown property:
        OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
        // to allow C/C++ style comments in JSON (non-standard, disabled by default)
        OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
        // to allow (non-standard) unquoted field names in JSON:
        OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
        // to allow use of apostrophes (single quotes), non standard
        OBJECT_MAPPER.configure(JsonParser.Feature.ALLOW_SINGLE_QUOTES, true);
        // disable fast failed
        OBJECT_MAPPER.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    }

    public static <T> String pojo2json(T t) {
        if (t == null) return null;
        try {
            return OBJECT_MAPPER.writeValueAsString(t);
        } catch (JsonProcessingException e) {
            log.warn("pojo2json failed: {}", e.getMessage());
            return "";
        }
    }

    public static <T> T json2pojo(String json, Class<T> type) {
        json = json == null ? "" : json.trim();
        if (StringUtils.isEmpty(json)) {
            return null;
        }
        try {
            return OBJECT_MAPPER.readValue(json, type);
        } catch (IOException e) {
            log.warn("json2pojo failed: {}", e.getMessage());
            return null;
        }
    }

    public static String fastToJson(Object o) {
        if (o == null) return null;
        return JSON.toJSONString(o,
                SerializerFeature.WriteEnumUsingName,
                SerializerFeature.WriteNullNumberAsZero,
                SerializerFeature.WriteNullBooleanAsFalse,
                SerializerFeature.WriteDateUseDateFormat);
    }

    public static String fastExcludeToJson(Object o, Class clazz, String... excludes) {
        if (o == null) return null;

        SimplePropertyPreFilter filter = new SimplePropertyPreFilter();

        for (String exclude : excludes) {
            filter.getExcludes().add(exclude);
        }

        return JSON.toJSONString(o, filter,
                SerializerFeature.WriteEnumUsingName,
                SerializerFeature.WriteNullNumberAsZero,
                SerializerFeature.WriteNullBooleanAsFalse,
                SerializerFeature.WriteDateUseDateFormat);
    }

    public static <T> T fastToObject(String json, Class<T> clazz) {
        json = json == null ? "" : json.trim();

        if (StringUtils.isEmpty(json)) {
            return null;
        }
        return JSON.parseObject(json, clazz, Feature.IgnoreNotMatch);
    }
}
